import { HttpErrorResponse, HttpEvent, HttpHandler, HttpHeaders, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { inject, Injectable } from '@angular/core';
import { Observable, throwError, from } from 'rxjs';
import { catchError, filter, switchMap } from 'rxjs/operators';

import { RefreshTokenKey, TokenKey } from '@config/constant';
import { NzSafeAny } from 'ng-zorro-antd/core/types';
import { NzMessageService } from 'ng-zorro-antd/message';

import { WindowService } from '../common/window.service';
import { StatusCode } from '../http/base-http.service';
import { LoginService, TokenResult } from '../http/login/login.service';

interface CustomHttpConfig {
  headers?: HttpHeaders;
}

const specialHandleUrl: string[] = ['upload', 'ImportScore', 'ImportStudent', 'ScanImages', 'ScanZip', 'login', 'changePassword'];

@Injectable()
export class HttpInterceptorService implements HttpInterceptor {
  windowServe = inject(WindowService);
  message = inject(NzMessageService);
  authService = inject(LoginService); // Inject AuthService

  intercept(req: HttpRequest<NzSafeAny>, next: HttpHandler): Observable<HttpEvent<NzSafeAny>> {
    const token = this.windowServe.getSessionStorage(TokenKey);
    let httpConfig: CustomHttpConfig = {};
    const urlArrays: string[] = req.url.split('/');
    if (!!token) {
      httpConfig = { headers: req.headers.set(TokenKey, token) };
    }
    let copyReq = req.clone(httpConfig);
    let urlPath = urlArrays[urlArrays.length - 1];
    if (urlPath.indexOf('?') > -1) {
      urlPath = urlPath.split('?')[0];
    }
    if (!specialHandleUrl.some(r => r.toLocaleLowerCase() === urlPath.toLocaleLowerCase())) {
      copyReq = copyReq.clone({
        setHeaders: {
          'Content-Type': 'application/json'
        }
      });
    }
    return next.handle(copyReq).pipe(
      filter(e => e.type !== 0),
      catchError(error => {
        const refreshToken = this.windowServe.getSessionStorage(RefreshTokenKey);
        if (error instanceof HttpErrorResponse && error.status === StatusCode.UnAuthorized && refreshToken) {
          // If 401 error, try to refresh the token
          return this.authService.refreshToken(refreshToken).pipe(
            switchMap((tokenResult: TokenResult[]) => {
              // Clone the request with the new token
              const newReq = req.clone({
                setHeaders: {
                  Authorization: `Bearer ${tokenResult[0].token}`
                }
              });
              return next.handle(newReq);
            }),
            catchError(err => this.handleError(err))
          );
        } else {
          return this.handleError(error);
        }
      })
    );
  }

  private handleError(error: HttpErrorResponse): Observable<never> {
    const status = error.status;
    let errMsg = '';
    if (status === 0) {
      errMsg = '网络出现未知的错误，请检查您的网络。';
    }
    if (status >= 300 && status < 400) {
      errMsg = `请求被服务器重定向，状态码为${status}`;
    }
    if (status >= 400 && status < 500) {
      errMsg = `客户端出错，可能是发送的数据有误，状态码为${status}`;
    }
    if (status >= 500) {
      errMsg = `服务器发生错误，状态码为${status}`;
    }

    return throwError(() => {
      return {
        code: status,
        message: errMsg
      };
    });
  }
}
